﻿'' GoogleCode - http://code.google.com/p/outlook-4-you/
'' GNU GPL v3 Licencing

Imports Microsoft.Office.Interop.Outlook
Imports System.Diagnostics

Public Class QueueAddin '' This plugin holds information on build tasks
#Region "Declarations"
#Region "UI declarations"
    Private WithEvents cb As Office.CommandBar
    Private WithEvents cbbRequest As Office.CommandBarButton
    Private WithEvents cbbLeave As Office.CommandBarButton
    Private WithEvents cbbBuild As Office.CommandBarButton
    Private Const cb_name As String = "Queue" ''This should be unique to your bar
#End Region

#Region "Inspector UI"
    Private WithEvents cbt As Office.CommandBar
    Private WithEvents tbbCheck As Office.CommandBarButton
    Private WithEvents tbbCompile As Office.CommandBarButton
#End Region

#Region "Variable"
    Private func As Functional
    Private WithEvents objApt As Outlook.AppointmentItem
    Private WithEvents objMail As Outlook.MailItem
    Private WithEvents objInspector As Outlook.Inspectors
    Private WithEvents CalItems, InboxItems, BuildItems As Outlook.Items
    Private olCal, olMail, olBuilds, olTasks As Outlook.Folder
    Private cLeave, pLeave, fLeave As Double
#End Region
#End Region

#Region "VSTO required"
    Private Sub ThisAddIn_Startup(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Startup
        olCal = Me.Application.GetNamespace("MAPI").GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar)
        olMail = Me.Application.GetNamespace("MAPI").GetDefaultFolder(OlDefaultFolders.olFolderInbox)
        olBuilds = olMail.Parent.folders("Builds")
        olTasks = Me.Application.GetNamespace("MAPI").GetDefaultFolder(OlDefaultFolders.olFolderTasks)
        objInspector = Application.Inspectors
        AddHandler objInspector.NewInspector, AddressOf objInspector_NewInspector
        Add_Menubar()
        '' Add handlers for apps
        Build_Handler()
        '' Call button updates
        Button_Summary()
    End Sub
    Private Sub ThisAddIn_Shutdown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shutdown

    End Sub
#End Region

#Region "UI"
    Private Sub Add_Menubar()
        '' Setup Commandbar
        Try
            cb = Application.CommandBars(cb_name)
        Catch ex As MissingMemberException
            cb = Me.Application.ActiveExplorer.CommandBars.Add(cb_name, Office.MsoBarPosition.msoBarRight, False, True)
        End Try
        cb.Visible = True

        cbbBuild = cb.Controls.Add(Office.MsoControlType.msoControlButton, , , 1, True)
        With cbbBuild
            .Style = Microsoft.Office.Core.MsoButtonStyle.msoButtonIconAndCaption
            .Caption = "Builds"
            .FaceId = 3197  '3197 file instack, 3975 linked comps, 0627 barcode, 2173 wand, 2950 smiley, 0643 POW
            .Tag = "css"
            .Visible = True
        End With
        AddHandler cbbBuild.Click, AddressOf Me.cbbBuild_Click
    End Sub    '' Creates button on commandbar
#End Region

#Region "Events"
    Private Sub cbbBuild_Click()
        MsgBox("Some day I'll report something")
    End Sub
#End Region

#Region "Outlook tasks"
    Private Sub objInspector_NewInspector(ByVal Inspector As Microsoft.Office.Interop.Outlook.Inspector)
        Dim item As Object = Inspector.CurrentItem

        If (TypeOf item Is Outlook.TaskItem) Then
            cbt = Inspector.CommandBars.Add(cb_name, Office.MsoBarPosition.msoBarTop, False, True)
            cbt.Visible = True
            cbt.Protection = Microsoft.Office.Core.MsoBarProtection.msoBarNoCustomize

            tbbCheck = cbt.Controls.Add(Office.MsoControlType.msoControlButton, , , 1, True)
            With tbbCheck
                .Style = Microsoft.Office.Core.MsoButtonStyle.msoButtonIconAndWrapCaptionBelow
                .Caption = "Check Source"
                .FaceId = 3197  '3197 file instack, 3975 linked comps, 0627 barcode, 2173 wand, 2950 smiley
                .Tag = "C"
                .Visible = True
            End With
            AddHandler tbbCheck.Click, AddressOf Me.tbbCheck_Click

            tbbCompile = cbt.Controls.Add(Office.MsoControlType.msoControlButton, , , 1, True)
            With tbbCompile
                .Style = Microsoft.Office.Core.MsoButtonStyle.msoButtonIconAndWrapCaptionBelow
                .Caption = "Ready for building"
                .FaceId = 3975  '3197 file instack, 3975 linked comps, 0627 barcode, 2173 wand, 2950 smiley
                .Tag = "Go"
                .Visible = True
            End With
            AddHandler tbbCompile.Click, AddressOf Me.tbbCompile_Click
        End If
    End Sub  '' Does something based on Inspector Type
    Public Shared Function Send_email(ByVal too As String, ByVal subj As String, ByVal body As String) As Boolean
        Dim request As Outlook.MailItem = Globals.QueueAddin.Application.CreateItem(Outlook.OlItemType.olMailItem)
        Try
            With request
                .Subject = subj
                .Body = body
                .To = too
                .Importance = OlImportance.olImportanceHigh
                .Send()
            End With
            Return True
        Catch ex As SystemException
            MsgBox("Could not send email, Sorry")
            Return False
        End Try
    End Function
    Public Shared Function Create_build(ByVal ref As String, ByVal stream As String, ByVal sender As String, ByRef GUID As String) As Boolean
        Dim build As Outlook.TaskItem = Globals.QueueAddin.Application.CreateItem(Outlook.OlItemType.olTaskItem)

        Try
            Dim params As String() = stream.Split(",")

            Dim srcs As String = params(3).Replace("$$", vbCrLf & vbTab)
            Dim src As String = srcs.Replace("##", vbTab)

            Dim comps As String = params(4).Replace("$$", vbCr & vbTab)
            Dim comp As String = comps.Replace("##", vbTab)

            Dim sql As String = params(5).Replace("$$", vbCrLf)
            Dim imp As String = params(6).Replace("$$", vbCrLf)
            Dim info As String = params(7).Replace("$$", vbCrLf)

            Dim i As Integer = sender.LastIndexOf("CN=") + 3
            Dim sentname As String = sender.Substring(i, sender.Length - (i))
            Dim body As String = "Sender: " & sender & vbCrLf & _
                                 "ID: " & ref & vbCrLf & _
                                 "Product: " & params(0).ToString & vbCrLf & _
                                 "Release: " & params(1).ToString & vbCrLf & _
                                 "Description: " & params(2).ToString & vbCrLf & _
                                 "Sourcefiles:" & vbCrLf & vbTab & src & vbCrLf & _
                                 "Components: " & vbCr & vbTab & comp & vbCr & _
                                 "SQLs: " & vbCrLf & vbTab & sql & vbCrLf & _
                                 "Impact Analysis: " & vbCr & imp & vbCr & _
                                 "Additional Information: " & vbCr & info
            With build
                .Subject = "Build Request - " & sentname
                .Body = body
                .StartDate = Now
                .DueDate = Now.AddDays(7)
                .ReminderTime = Now.AddDays(7)
                .Status = OlTaskStatus.olTaskNotStarted
                .Importance = OlImportance.olImportanceHigh
                .Save()
            End With

            GUID = build.EntryID
            Return True
        Catch ex As SystemException
            MsgBox("Could not create build " & ref.Substring(Len(ref) - 10, 10) & ", Sorry" & vbCrLf & ex.Message)
            Return False
        End Try
    End Function
    Private Function Update_buildID(ByVal ID As String) As Boolean
        BuildItems = olTasks.Items
        'Dim items As Outlook.Items = BuildItems.Restrict("[Subject] = 'Build Request'")
        For Each item In BuildItems
            If (TypeOf item Is Outlook.TaskItem) Then           ' Is it a task?
                Dim objTask = TryCast(item, Outlook.TaskItem)   ' Cast as task
                If objTask IsNot Nothing Then                   ' Not blank?

                    If objTask.EntryID = ID Then                ' Is the one we want?
                        ' Replace Request mail ID with Task ID
                        Dim params As String() = objTask.Body.Split(vbCrLf)
                        If params(1).Contains("ID:") Then
                            params(1) = "ID: " & ID
                        End If
                        ' Save task body
                        objTask.Body = ""
                        For i = 0 To params.Length - 1
                            objTask.Body &= params(i).ToString & vbCrLf
                        Next
                        objTask.Save()
                    End If

                End If
            End If
        Next
    End Function
#End Region

#Region "Queue Specific code"
    Private Sub Build_Handler()
        Try
            AddHandler Me.Application.NewMailEx, AddressOf Mail_Sorting
            AddHandler olTasks.Items.ItemAdd, AddressOf Button_Summary
            AddHandler olTasks.Items.ItemChange, AddressOf Build_Check
        Catch ex As System.Exception
            MsgBox("Unable to AddHandler to Inbox Items in MailItem_Handler" & vbCr & ex.Message.ToString, MsgBoxStyle.Information, "Appointment Monitor")
        End Try
    End Sub   ' AddHandlers to events
    Private Sub Mail_Sorting()

        Dim ID As String = ""
        InboxItems = olMail.Items
        Dim items As Outlook.Items = InboxItems.Restrict("[UnRead] = true")
        For Each item In items
            If (TypeOf item Is Outlook.MailItem) Then
                objMail = TryCast(item, Outlook.MailItem)
                If objMail IsNot Nothing Then

                    If objMail.Subject.ToString.Contains("Build Request") = True Then   '' Build Request?
                        If objMail.Subject.Substring(6) = "Request" Then                '' New Build Request?
                            Try
                                If Create_build(objMail.EntryID, objMail.Body, objMail.SenderEmailAddress, ID) = True Then
                                    Send_email(objMail.SenderEmailAddress, _
                                               "Build request received", _
                                               "Your build request has been received by buildbot and has been scheduled." & vbCrLf & _
                                               "Upon analysis you will receive a confirmation of standards email for the build" & vbCrLf & _
                                               "Your build reference is: " & ID)
                                    Update_buildID(ID)
                                Else
                                    MsgBox("Failed to create build task")
                                End If
                                objMail.Move(olBuilds)
                            Catch ex As SystemException
                                MsgBox("Unable to Sort Builds")
                            End Try
                        ElseIf objMail.Subject.Contains("Passed") Then                '' Sanity tested?
                            '' Parse email for GUID of build
                            'Time2CodeDrop(Guid)
                        End If
                    End If
                End If
            End If
        Next

    End Sub        ' What to do with new mail

    Private Sub Button_Summary()
        Dim newb As Integer = 0
        Dim pass As Integer = 0
        Dim fail As Integer = 0
        Dim built As Integer = 0
        Dim dtSoW, dtEoW As Date


        BuildItems = olTasks.Items
        'Dim items As Outlook.Items = BuildItems.Restrict("[Subject] = 'Build Request'")
        For Each item In BuildItems
            If (TypeOf item Is Outlook.TaskItem) Then
                Dim objTask = TryCast(item, Outlook.TaskItem)
                If objTask IsNot Nothing Then

                    If objTask.Subject.Contains("Build Request - ") Then
                        WeekStarts(dtSoW, dtEoW)
                        If objTask.DueDate > dtSoW And objTask.DueDate < dtEoW Then ' This weeks only
                            Select Case objTask.Status
                                Case OlTaskStatus.olTaskNotStarted  ' New build
                                    newb += 1
                                Case OlTaskStatus.olTaskInProgress  ' Passed build
                                    pass += 1
                                Case OlTaskStatus.olTaskDeferred    ' Failed build
                                    fail += 1
                                Case OlTaskStatus.olTaskComplete    ' Built build
                                    built += 1
                            End Select
                        End If
                    End If
                End If
            End If
        Next
        cbbBuild.Caption = "Builds: " & (newb + pass).ToString & "/" & (newb + pass + fail + built).ToString
    End Sub      ' Changes button text for build status

    Private Sub tbbCheck_Click()
        Dim errlog As String = ""
        Dim result As String = ""
        Dim summary As String = ""

        ' Grab Build
        Dim item As Object = Me.Application.ActiveInspector.CurrentItem
        Dim task As TaskItem = TryCast(item, TaskItem)
        Dim params As String() = task.Body.Split(vbCrLf)
        Dim sender As String = params(0).Substring(8, params(0).Length - 8)

        ' Subversion checking
        If CheckSource(errlog) = True Then
            result &= "The files you submitted to build passed source code checks." & vbCrLf & _
                    "You will be notified with further progress"
            summary &= "Change Inspection: PASSED"
        Else
            If errlog <> "" Then
                Dim errors As String() = errlog.Split(",")
                summary &= "Code Inspection: FAILED" & vbCrLf & vbTab & errors.Length - 1 & " Files had problems"
                result &= "The items below failed source code checks. Please fix the errors and resubmit your request" & vbCrLf
                For i = 0 To errors.Length - 1
                    result &= vbTab & errors(i).ToString & vbCrLf
                Next
            End If
        End If
        task.Body &= vbCrLf & vbCrLf & summary

        ' Pass or Reject
        Dim subject As String = "Build Request "
        Dim ID As String = params(1).Substring(4, params(1).Length - 4)
        If summary.Contains("PASSED") = False Then
            subject &= "Rejected - " & ID
            task.Subject = "Build Request Rejected - " & ID
            task.Status = OlTaskStatus.olTaskDeferred
            If Send_email(sender, subject, (summary & vbCrLf & result)) = True Then
                MsgBox("Build rejection sent")
            End If
        Else
            task.Subject = "Build Request Accepted - " & ID
            task.Status = OlTaskStatus.olTaskInProgress
            MsgBox("Build Updated")
        End If

        Me.Application.ActiveInspector.Close(OlInspectorClose.olSave)
        'task.Save()

    End Sub      ' Check Source code button
    Private Function CheckSource(ByRef errors As String) As Boolean
        Dim subjectext As String = ""
        Dim bodytext As String = ""
        Dim files As String()() = Nothing
        Dim two As String = ""
        Dim pass As Boolean = True
        Dim item As Object = Me.Application.ActiveInspector.CurrentItem
        If (TypeOf item Is TaskItem) Then
            Dim task As TaskItem = TryCast(item, TaskItem)
            If task IsNot Nothing Then

                '' Real Start
                Dim fi, ci As Integer
                ' Get source files to check
                Dim params As String() = task.Body.Split(vbCrLf)

                ' Where are the sourcefiles
                For i = 0 To params.Length - 1
                    If params(i).Contains("Sourcefiles:") Then
                        fi = i + 2
                    ElseIf params(i).Contains("Components:") Then
                        ci = i - 4
                    End If
                Next

                ' Check individual source files with TortoiseDiff
                'Dim k As Integer = 0
                For j = fi To ci
                    Dim srcfiles As String() = params(j).Split(vbTab)       '' (0) is unprintable char (1) is filepath (2) is revision
                    ' Create table of files and whether they pass/fail


                    '' Subversion diff with pass/fail (file, startrev, endrev)
                    If srcfiles.Length > 1 Then
                        Dim chk As New frmCheck
                        func.tortoise_diff(srcfiles(1).ToString, srcfiles(2) - 1, srcfiles(2))
                        If chk.ShowDialog = Windows.Forms.DialogResult.No Then
                            errors &= srcfiles(1).ToString & ","
                            pass = False
                        End If

                        ' Kill Tortoise
                        For Each p As Process In System.Diagnostics.Process.GetProcessesByName("TortoiseMerge")
                            Try
                                p.Kill()
                                p.WaitForExit()
                            Catch invalidException As InvalidOperationException
                                MsgBox("Process has already exited")
                            End Try
                        Next
                    End If
                Next

            End If
        End If
        If pass = False Then
            Return False
        Else
            Return True
        End If
    End Function    ' Check Source routine

    Private Sub tbbCompile_Click()
        ' Grab Build
        Dim item As Object = Me.Application.ActiveInspector.CurrentItem
        Dim task As TaskItem = TryCast(item, TaskItem)
        With task
            .PercentComplete = 10
            .Save()
        End With
    End Sub    ' Flag a build for compilation

    Private Sub Build_Check()
        BuildItems = olTasks.Items
        For Each item In BuildItems
            If (TypeOf item Is Outlook.TaskItem) Then
                Dim objTask = TryCast(item, Outlook.TaskItem)
                If objTask IsNot Nothing Then

                    If objTask.Subject.Contains("Build Request Accepted - ") Then
                        If objTask.Status = OlTaskStatus.olTaskInProgress Then
                            '' BUILD
                            Dim params As String() = objTask.Body.Split(vbCrLf)
                            Dim ID As String = ""
                            For i = 0 To params.Length - 1
                                If params(i).Contains("ID:") Then
                                    ID = params(i).ToString
                                End If
                            Next
                            MsgBox("Check Build environments")
                            MsgBox("Building " & ID)
                        End If
                    End If

                End If
            End If
        Next
    End Sub         ' What build stage are we in? Development or Regression testing

    Private Sub Time2CodeDrop(ByVal guid As String)
        '' Open build task
        '' Amend body with "Sanity testing: PASSED"
        '' Change .percentcomplete
        '' Parse Task Body
        '' Create drop folder
        '' Copy files to drop folder
        '' Create Deployment Instructions
        '' Send Drop Mail
    End Sub

    Private Function Search4Build(ByVal GUID As String, ByRef build As String) As Boolean
        BuildItems = olTasks.Items
        For Each item In BuildItems
            If (TypeOf item Is Outlook.TaskItem) Then
                Dim objTask = TryCast(item, Outlook.TaskItem)
                If objTask IsNot Nothing Then

                    If objTask.EntryID.ToString = GUID Then
                        If objTask.Body.ToString.Contains(GUID) = True Then
                            build &= objTask.Body.ToString  '' FTTB Use reverse email
                        End If
                    End If
                End If
            End If
        Next
    End Function
#End Region

#Region "Miscellaneous"
    Private Sub WeekStarts(ByRef Start As Date, ByRef dEnd As Date)
        Select Case DateAndTime.Now.DayOfWeek
            Case DayOfWeek.Monday
                Start = New Date(DateAndTime.Now.Year, DateAndTime.Now.Month, DateAndTime.Now.Day, 0, 0, 0)
                dEnd = DateAndTime.Now.AddDays(6)
            Case DayOfWeek.Tuesday
                Start = New Date(DateAndTime.Now.Year, DateAndTime.Now.Month, DateAndTime.Now.Day - 1, 0, 0, 0)
                dEnd = DateAndTime.Now.AddDays(5)
            Case DayOfWeek.Wednesday
                Start = New Date(DateAndTime.Now.Year, DateAndTime.Now.Month, DateAndTime.Now.Day - 2, 0, 0, 0)
                dEnd = DateAndTime.Now.AddDays(4)
            Case DayOfWeek.Thursday
                Start = New Date(DateAndTime.Now.Year, DateAndTime.Now.Month, DateAndTime.Now.Day - 3, 0, 0, 0)
                dEnd = DateAndTime.Now.AddDays(3)
            Case DayOfWeek.Friday
                Start = New Date(DateAndTime.Now.Year, DateAndTime.Now.Month, DateAndTime.Now.Day - 4, 0, 0, 0)
                dEnd = DateAndTime.Now.AddDays(2)
            Case DayOfWeek.Saturday
                Start = New Date(DateAndTime.Now.Year, DateAndTime.Now.Month, DateAndTime.Now.Day - 5, 0, 0, 0)
                dEnd = DateAndTime.Now.AddDays(1)
            Case DayOfWeek.Sunday
                Start = New Date(DateAndTime.Now.Year, DateAndTime.Now.Month, DateAndTime.Now.Day - 6, 0, 0, 0)
                dEnd = DateAndTime.Now
        End Select
    End Sub
#End Region
End Class
